To start off with, let’s load data and libs:

library(tidyverse)
Loading tidyverse: ggplot2
Loading tidyverse: tibble
Loading tidyverse: tidyr
Loading tidyverse: readr
Loading tidyverse: purrr
Loading tidyverse: dplyr
Conflicts with tidy packages ----------------------------------------------------------------
filter(): dplyr, stats
lag():    dplyr, stats
library(CKMRsim)
library(stringr)
library(readxl)
#meta <- readRDS("../data/processed/meta-data-tibble.rds") # not worrying about meta data right now...
genos <- readRDS("../data/processed/called_genos_na_explicit.rds") #%>%
  #filter(NMFS_DNA_ID %in% meta$NMFS_DNA_ID)  # drop those we don't have meta data for
samples <- readRDS("../data/processed/sample-sheet-tibble.rds") #%>%
  #filter(NMFS_DNA_ID %in% meta$NMFS_DNA_ID)

Some initial filters

Take highest read-depth call for multiply-genotyped DNA_IDs

I’m not sure if there are any of these, but best to leave it in here… particularly for the re-genotyped fish from Brittany’s OSU samples.

Now, here is a harder operation: if an individual is multiply-genotyped, take the genotype with the highest total read depth.

# slow-ish function to get the total read depth column
tdepth <- function(a, d) {
  if(any(is.na(a))) {
    return(NA)
  }
  if(a[1]==a[2]) {
    return(d[1])
  } else {
    return(d[1] + d[2])
  }
  
}
# this takes the highest read-depth instance of each duplicately-genotyped individual.
geno_one_each <- genos %>%
  group_by(NMFS_DNA_ID, locus, gtseq_run, id) %>%
  mutate(total_depth = tdepth(allele, depth)) %>%
  ungroup() %>%
  arrange(NMFS_DNA_ID, locus, total_depth, gtseq_run, id, depth) %>%
  group_by(NMFS_DNA_ID, locus) %>%
  mutate(rank = 1:n()) %>%
  ungroup() %>%
  filter(rank <= 2)

Remove the 6 loci which Hayley has been removing

# read in a list of the 6 loci
to_remove <- read_csv("../data/loci_to_remove.csv")
Parsed with column specification:
cols(
  locus = col_character()
)
# only keep the loci that are not those 6
keepers <- geno_one_each %>%
  anti_join(., to_remove, by = "locus")
# that should leave 90 loci  

Toss out indivs with missing data at more than 15 loci

Now, toss out any individual with fewer than 75 non-missing loci

no_hi_missers <- keepers %>% 
  group_by(NMFS_DNA_ID) %>%
  filter(sum(!is.na(allele)) >= (75*2))

So, we started with 1674 and after filtering out indivs with fewer than 75 genotyped loci, we were left with 1655 individuals. Those are the ones that we will run through rubias to identify to species.

Read in baseline genotypes and remove loci and individuals with too much missing data

# get the data frames into the same format
no_hi_missers2 <- no_hi_missers %>%
  dplyr::select(NMFS_DNA_ID, locus, gene_copy, allele) %>%
  rename(indiv = NMFS_DNA_ID) %>%
  mutate(sample_type = "mixture") %>%
  mutate(repunit = NA) %>%
  mutate(collection = "osu_samples")
# reorder
no_hi_missers2[, c(5:7,1:4)]

# combine the data into a single df
alleles <- bind_rows(spp.id2, no_hi_missers2)
alleles

We are going to do this by turning alleles into integers and spreading it and then getting it into the right format to run rubias.

# first make integers of the alleles
alle_idxs <- alleles %>% 
  #dplyr::select(NMFS_DNA_ID, locus, gene_copy, allele) %>%
  group_by(locus) %>%
  mutate(alleidx = as.integer(factor(allele, levels = unique(allele)))) %>%
  ungroup() %>%
  arrange(indiv, locus, alleidx) # rubias can handle NA's, so no need to change them to 0's
  
# select just the columns to retain and spread the alleles
alle_idx2 <- alle_idxs[,-7]
  
two_col <- alle_idx2 %>%
  unite(loc, locus, gene_copy, sep = ".") %>%
  spread(loc, alleidx)
two_col
# write this file to a thing that can be read-into other softwares
#two_col %>%
# write_csv("csv_outputs/genos_two_col.csv")

Okay, after some reading, it looks like I need to use infer_mixture in rubias. Which require two separate data frames, one with the reference genotypes and the other with the mixture.

I’ll split the data frame that I created, but it needed to be bunged together for the conversion of alleles to integers.

# split up the reference and mixture data frames
sp_mix <- two_col %>%
  filter(sample_type == "mixture")
sp_ref <- two_col %>%
  filter(sample_type == "reference")
# Now that the data are in the corret format, load Rubias
library(rubias)
# perform self-assignment of reference samples
ref_self <- self_assign(sp_ref, gen_start_col = 5)
Summary Statistics:

1403 Individuals in Sample

90 Loci: Plate_1_A01_Sat_GW603857_consensus.1, Plate_1_A11_Sat_GE820299_consensus.1, Plate_2_A09_Sat_EW986980_consensus.1, Plate_2_C08_Sat_EW987116_consensus.1, Plate_2_G06_Sat_EW987118_consensus.1, Plate_3_C03_Sat_GE798118_consensus.1, Plate_4_E10_Sat_EW976030_consensus.1, Plate_4_G06_Sat_EW976181_consensus.1, tag_id_1049.1, tag_id_108.1, tag_id_1184.1, tag_id_1229.1, tag_id_1272.1, tag_id_1366.1, tag_id_1428.1, tag_id_143.1, tag_id_1441.1, tag_id_1449.1, tag_id_1471.1, tag_id_1498.1, tag_id_1558.1, tag_id_1576.1, tag_id_1598.1, tag_id_1604.1, tag_id_1613.1, tag_id_162.1, tag_id_1652.1, tag_id_170.1, tag_id_1708.1, tag_id_1748.1, tag_id_1751.1, tag_id_1762.1, tag_id_179.1, tag_id_1804.1, tag_id_1808.1, tag_id_1810.1, tag_id_1836.1, tag_id_1850.1, tag_id_1880.1, tag_id_1889.1, tag_id_1915.1, tag_id_1950.1, tag_id_1961.1, tag_id_1966.1, tag_id_1982.1, tag_id_1994.1, tag_id_1999.1, tag_id_2008.1, tag_id_2009.1, tag_id_2017.1, tag_id_2062.1, tag_id_2082.1, tag_id_2114.1, tag_id_2134.1, tag_id_2155.1, tag_id_2178.1, tag_id_2182.1, tag_id_220.1, tag_id_2203.1, tag_id_221.1, tag_id_2214.1, tag_id_2237.1, tag_id_2247.1, tag_id_2258.1, tag_id_2301.1, tag_id_2319.1, tag_id_2368.1, tag_id_2499.1, tag_id_250.1, tag_id_2607.1, tag_id_2635.1, tag_id_265.1, tag_id_325.1, tag_id_402.1, tag_id_410.1, tag_id_436.1, tag_id_55.1, tag_id_572.1, tag_id_67.1, tag_id_770.1, tag_id_788.1, tag_id_843.1, tag_id_855.1, tag_id_874.1, tag_id_875.1, tag_id_879.1, tag_id_913.1, tag_id_942.1, tag_id_981.1, tag_id_987.1

48 Reporting Units: Salutus, Satrovirens, Sauriculatus, Saurora, Sbabcocki, Scarnatus, Scaurinus, Schlorostictus, Schrysomelas, Sconstellatus, Scrameri, Sdallii, Sdiaconus, Sdiploproa, Selongatus, Semphaeus, Sentomelas, Sflavidus, Sgoodei, Shelvomaculatus, Shopkinsi, Sjordani, Slevis, Smaliger, Smelanops, Smelanostomus, Sminiatus, Smystinus, Snebulosus, Snigrocinctus, Soculatus, Sovalis, Spaucispinis, Spinniger, Sproriger, Srastrelliger, Sreedi, Srosaceus, Sruberrimus, Srubrivinctus, Srufus, Ssaxicola, Ssemicinctus, Sserranoides, Sserriceps, Sumbrosus, Swilsoni, Szacentrus

48 Collections: Salutus, Satrovirens, Sauriculatus, Saurora, Sbabcocki, Scarnatus, Scaurinus, Schlorostictus, Schrysomelas, Sconstellatus, Scrameri, Sdallii, Sdiaconus, Sdiploproa, Selongatus, Semphaeus, Sentomelas, Sflavidus, Sgoodei, Shelvomaculatus, Shopkinsi, Sjordani, Slevis, Smaliger, Smelanops, Smelanostomus, Sminiatus, Smystinus, Snebulosus, Snigrocinctus, Soculatus, Sovalis, Spaucispinis, Spinniger, Sproriger, Srastrelliger, Sreedi, Srosaceus, Sruberrimus, Srubrivinctus, Srufus, Ssaxicola, Ssemicinctus, Sserranoides, Sserriceps, Sumbrosus, Swilsoni, Szacentrus

5.03365803437079% of allelic data identified as missing
# and take a quick look at those assignments
ref_self %>%
  filter(inferred_repunit == repunit) %>%
  filter(scaled_likelihood > 0.95)
# perform mixture-assignment on baseline colony samples
mix_assign <- infer_mixture(reference = sp_ref, mixture = sp_mix, gen_start_col = 5, method = "MCMC", reps = 2000, burn_in = 100)
Collating data; compiling reference allele frequencies, etc.   time: 1.50 seconds
Computing reference locus specific means and variances for computing mixture z-scores   time: 0.30 seconds
Working on mixture collection: osu_samples with 1436 individuals
  calculating log-likelihoods of the mixture individuals.   time: 0.30 seconds
  performing 100 burn-in and 2000 more sweeps of method "MCMC"   time: 1.79 seconds
  tidying output into a tibble.   time: 0.17 seconds
# That was fast, let's take a look
head(mix_assign)
$mixing_proportions

$indiv_posteriors

$mix_prop_traces

$bootstrapped_proportions
# the individual data is in 
mix_assign$indiv_posteriors %>%
  arrange(desc(log_likelihood))
# are there any rockfish that don't seem like the correct species is in the reference?
osu_assignments <- mix_assign$indiv_posteriors %>%
  filter(PofZ == 1)
osu_assign2 <- osu_assignments[,-10]
#write_csv(osu_assign2, "csv_outputs/osu_assignments.csv")
osu_assign2

The posterior means of group membership in each collection is in the PofZ column - there are 1,220 individuals with a PofZ = 1.

Maybe some of these samples just had a PofZ larger/smaller than 1? (eventually I will update brit_data with all of the appropriate meta data for this project.)

# I think there are individual assignments for each sample to each reference.
# I want to take only the top assignment for each sample.
kept_assignments <- mix_assign$indiv_posteriors %>%
  group_by(indiv) %>%
  filter(PofZ > 0.95) %>%
  arrange(desc(PofZ))
kept_assignments

Using Hayley’s threshold of 0.95 for the PofZ, we have 1,435 individuals retained.

Now take a look at which fish from Brittany’s samples are included:

# using the data I read in previously
tmp2 <- kept_assignments %>%
  left_join(., brit_data, by = c("indiv" = "NMFS_DNA_ID"))
brit_assign <- tmp2[1:21]
# which of brittany's samples still don't have genotype info?
brit_data %>%
  anti_join(., kept_assignments, by = c("NMFS_DNA_ID" = "indiv"))

That didn’t increase the number of samples retained by much…

Are there really 375 samples that don’t have genotypes?

all_assign <- mix_assign$indiv_posteriors %>%
  group_by(indiv)
# which of brittany's samples don't have genotype info?
brit_data %>%
  anti_join(., all_assign, by = c("NMFS_DNA_ID" = "indiv"))

Okay, those 375 samples just aren’t in the data set. They’re not just filtered out by the 0.95 PofZ assignment threshold.

head(brit_data) # here is the "SPECIES" column

kept_assignments %>%
  left_join(., brit_data, by = c("indiv" = "NMFS_DNA_ID")) %>%
  select(1:9,11:30) %>%
  write_csv("csv_outputs/osu_kept_assignments.csv")
  

Repository meta data for Brittany’s samples

batch_4792 <- read_csv("../extdata/batch4792.csv")
Missing column names filled in: 'X16' [16], 'X18' [18]Parsed with column specification:
cols(
  .default = col_character(),
  SAMPLE_ID = col_integer(),
  BATCH_ID = col_integer(),
  LENGTH = col_double(),
  WEIGHT = col_double()
)
See spec(...) for full column specifications.
number of columns of result is not a multiple of vector length (arg 1)700 parsing failures.
row # A tibble: 5 x 5 col     row   col   expected     actual                       file expected   <int> <chr>      <chr>      <chr>                      <chr> actual 1    16  <NA> 22 columns 20 columns '../extdata/batch4792.csv' file 2    17  <NA> 22 columns 20 columns '../extdata/batch4792.csv' row 3    18  <NA> 22 columns 20 columns '../extdata/batch4792.csv' col 4    19  <NA> 22 columns 20 columns '../extdata/batch4792.csv' expected 5    20  <NA> 22 columns 20 columns '../extdata/batch4792.csv'
... ................. ... .............................................................. ........ .............................................................. ...... .............................................................. .... .............................................................. ... .............................................................. ... .............................................................. ........ ..............................................................
See problems(...) for more details.
batch_4969 <- read_csv("../extdata/batch4969.csv")
Missing column names filled in: 'X16' [16], 'X18' [18]Parsed with column specification:
cols(
  .default = col_character(),
  BATCH_ID = col_integer(),
  LENGTH = col_double(),
  WEIGHT = col_integer()
)
See spec(...) for full column specifications.
number of columns of result is not a multiple of vector length (arg 1)242 parsing failures.
row # A tibble: 5 x 5 col     row   col   expected     actual                       file expected   <int> <chr>      <chr>      <chr>                      <chr> actual 1    16  <NA> 22 columns 21 columns '../extdata/batch4969.csv' file 2    17  <NA> 22 columns 21 columns '../extdata/batch4969.csv' row 3    18  <NA> 22 columns 21 columns '../extdata/batch4969.csv' col 4    19  <NA> 22 columns 21 columns '../extdata/batch4969.csv' expected 5    20  <NA> 22 columns 21 columns '../extdata/batch4969.csv'
... ................. ... .............................................................. ........ .............................................................. ...... .............................................................. .... .............................................................. ... .............................................................. ... .............................................................. ........ ..............................................................
See problems(...) for more details.
# somehow the structure for the sample IDs is different in the two files...
# change that.
batch_4792$SAMPLE_ID <- as.character(batch_4792$SAMPLE_ID)
# bind those things together
meta <- bind_rows(batch_4969, batch_4792)

The meta file should contain all the samples for Brittany’s project.

192 samples. That’s still an unfortunate lot. I wonder if they are the same samples that didn’t genotype well last time?

Still 192 samples!

Of primary concern is whether we actually genotyped these at all. Let’s go back to the data.

Yup. The 192 samples are in the hi-missers data - they had lots of missing genotypes.

Looking at the success of re-genotyped samples

# just the samples from gtseq 63
gtseq63 <- samples %>%
  filter(gtseq_run == "gtseq63")

# now add assignments just for those samples
gtseq63 %>%
  left_join(., kept_assignments, by = c("NMFS_DNA_ID" = "indiv")) %>%
  select(1:2, 5:7, 17:22) %>%
  #write_csv("csv_outputs/gtseq63_assignments.csv")
  filter(ssBOX_ID == "R374") #%>%
  #write_csv("csv_outputs/gtseq63_R374_assignments.csv")

Here’s what Cassie said was in that run: This run has box R373 and two mixed plates (1 of those mixed plates is partial). Plate 1 has the samples from plate R374 that need species ID – Brittany’s samples in 1A - 3A; samples for Helen Killeen in 3B - 4A; two re-picks from your NFS project in 4B and 4C; and ONE tentative Mexican rockfish in 4D. It also has re-runs for Brittany’s project. The two NSF re-picks are highlighted in the attached list of black and yellow sibs that you gave me. We re-extracted these since there was tissue remaining and we also re-ran the original DNA extracts in this run. Plate 2rr are all re-runs including your NSF black and yellow sibs and the rest of the failed samples from Bailey’s run for Brittany’s project.

gtseq63 %>%
  filter(ssBOX_ID == "R282")
# which samples from gtseq63 don't have kept assignments?
gtseq63 %>%
  anti_join(., kept_assignments, by = c("NMFS_DNA_ID" = "indiv")) %>%
  filter(ssBOX_ID == "R133")

All the samples from R373 were not re-runs. (23 samples) The 4 samples that failed from R374 were for Helen Killeen.

47 -27 = 20 samples that failed from the re-runs? Was that out of 108 total?

And if we did re-run all of Brittany’s fish from previous runs, is the majority of the missing data from the new samples?

LS0tCnRpdGxlOiAiQWdncmVncmF0ZSBNdWx0aXBseS1nZW5vdHlwZWQgaW5kaXZzIGFuZCBhc3NpZ24gcm9ja2Zpc2ggd2l0aCBydWJpYXMiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQotLS0KCgoKClRvIHN0YXJ0IG9mZiB3aXRoLCBsZXQncyBsb2FkIGRhdGEgYW5kIGxpYnM6CmBgYHtyIGxvYWQtc3R1ZmZ9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KENLTVJzaW0pCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShyZWFkeGwpCgojbWV0YSA8LSByZWFkUkRTKCIuLi9kYXRhL3Byb2Nlc3NlZC9tZXRhLWRhdGEtdGliYmxlLnJkcyIpICMgbm90IHdvcnJ5aW5nIGFib3V0IG1ldGEgZGF0YSByaWdodCBub3cuLi4KZ2Vub3MgPC0gcmVhZFJEUygiLi4vZGF0YS9wcm9jZXNzZWQvY2FsbGVkX2dlbm9zX25hX2V4cGxpY2l0LnJkcyIpICMlPiUKICAjZmlsdGVyKE5NRlNfRE5BX0lEICVpbiUgbWV0YSROTUZTX0ROQV9JRCkgICMgZHJvcCB0aG9zZSB3ZSBkb24ndCBoYXZlIG1ldGEgZGF0YSBmb3IKc2FtcGxlcyA8LSByZWFkUkRTKCIuLi9kYXRhL3Byb2Nlc3NlZC9zYW1wbGUtc2hlZXQtdGliYmxlLnJkcyIpICMlPiUKICAjZmlsdGVyKE5NRlNfRE5BX0lEICVpbiUgbWV0YSROTUZTX0ROQV9JRCkKYGBgCgoKIyMgU29tZSBpbml0aWFsIGZpbHRlcnMKCiMjIyBUYWtlIGhpZ2hlc3QgcmVhZC1kZXB0aCBjYWxsIGZvciBtdWx0aXBseS1nZW5vdHlwZWQgRE5BX0lEcwoKSSdtIG5vdCBzdXJlIGlmIHRoZXJlIGFyZSBhbnkgb2YgdGhlc2UsIGJ1dCBiZXN0IHRvIGxlYXZlIGl0IGluIGhlcmUuLi4KcGFydGljdWxhcmx5IGZvciB0aGUgcmUtZ2Vub3R5cGVkIGZpc2ggZnJvbSBCcml0dGFueSdzIE9TVSBzYW1wbGVzLgoKTm93LCBoZXJlIGlzIGEgaGFyZGVyIG9wZXJhdGlvbjogaWYgYW4gaW5kaXZpZHVhbCBpcyBtdWx0aXBseS1nZW5vdHlwZWQsIHRha2UgdGhlCmdlbm90eXBlIHdpdGggdGhlIGhpZ2hlc3QgdG90YWwgcmVhZCBkZXB0aC4gIApgYGB7ciB0YWtlLWp1c3Qtb25lfQojIHNsb3ctaXNoIGZ1bmN0aW9uIHRvIGdldCB0aGUgdG90YWwgcmVhZCBkZXB0aCBjb2x1bW4KdGRlcHRoIDwtIGZ1bmN0aW9uKGEsIGQpIHsKICBpZihhbnkoaXMubmEoYSkpKSB7CiAgICByZXR1cm4oTkEpCiAgfQogIGlmKGFbMV09PWFbMl0pIHsKICAgIHJldHVybihkWzFdKQogIH0gZWxzZSB7CiAgICByZXR1cm4oZFsxXSArIGRbMl0pCiAgfQogIAp9CiMgdGhpcyB0YWtlcyB0aGUgaGlnaGVzdCByZWFkLWRlcHRoIGluc3RhbmNlIG9mIGVhY2ggZHVwbGljYXRlbHktZ2Vub3R5cGVkIGluZGl2aWR1YWwuCmdlbm9fb25lX2VhY2ggPC0gZ2Vub3MgJT4lCiAgZ3JvdXBfYnkoTk1GU19ETkFfSUQsIGxvY3VzLCBndHNlcV9ydW4sIGlkKSAlPiUKICBtdXRhdGUodG90YWxfZGVwdGggPSB0ZGVwdGgoYWxsZWxlLCBkZXB0aCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBhcnJhbmdlKE5NRlNfRE5BX0lELCBsb2N1cywgdG90YWxfZGVwdGgsIGd0c2VxX3J1biwgaWQsIGRlcHRoKSAlPiUKICBncm91cF9ieShOTUZTX0ROQV9JRCwgbG9jdXMpICU+JQogIG11dGF0ZShyYW5rID0gMTpuKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBmaWx0ZXIocmFuayA8PSAyKQpgYGAKCiMjIyBSZW1vdmUgdGhlIDYgbG9jaSB3aGljaCBIYXlsZXkgaGFzIGJlZW4gcmVtb3ZpbmcKCmBgYHtyIHJlbW92ZS1sb2NpfQojIHJlYWQgaW4gYSBsaXN0IG9mIHRoZSA2IGxvY2kKdG9fcmVtb3ZlIDwtIHJlYWRfY3N2KCIuLi9kYXRhL2xvY2lfdG9fcmVtb3ZlLmNzdiIpCgojIG9ubHkga2VlcCB0aGUgbG9jaSB0aGF0IGFyZSBub3QgdGhvc2UgNgprZWVwZXJzIDwtIGdlbm9fb25lX2VhY2ggJT4lCiAgYW50aV9qb2luKC4sIHRvX3JlbW92ZSwgYnkgPSAibG9jdXMiKQoKIyB0aGF0IHNob3VsZCBsZWF2ZSA5MCBsb2NpICAKYGBgCgoKIyMjIFRvc3Mgb3V0IGluZGl2cyB3aXRoIG1pc3NpbmcgZGF0YSBhdCBtb3JlIHRoYW4gMTUgbG9jaQpOb3csIHRvc3Mgb3V0IGFueSBpbmRpdmlkdWFsIHdpdGggZmV3ZXIgdGhhbiA3NSBub24tbWlzc2luZyBsb2NpCmBgYHtyIHRvc3MtbWlzc2Vyc30Kbm9faGlfbWlzc2VycyA8LSBrZWVwZXJzICU+JSAKICBncm91cF9ieShOTUZTX0ROQV9JRCkgJT4lCiAgZmlsdGVyKHN1bSghaXMubmEoYWxsZWxlKSkgPj0gKDc1KjIpKQpgYGAKU28sIHdlIHN0YXJ0ZWQgd2l0aCBgciBsZW5ndGgodW5pcXVlKGdlbm9fb25lX2VhY2gkTk1GU19ETkFfSUQpKWAgCmFuZCBhZnRlciBmaWx0ZXJpbmcgb3V0IGluZGl2cyB3aXRoIGZld2VyIHRoYW4gNzUgZ2Vub3R5cGVkIGxvY2ksIHdlIHdlcmUgbGVmdCB3aXRoIApgciBsZW5ndGgodW5pcXVlKG5vX2hpX21pc3NlcnMkTk1GU19ETkFfSUQpKWAgaW5kaXZpZHVhbHMuICBUaG9zZSBhcmUgdGhlIG9uZXMgdGhhdAp3ZSB3aWxsIHJ1biB0aHJvdWdoIHJ1YmlhcyB0byBpZGVudGlmeSB0byBzcGVjaWVzLgoKIyMgUmVhZCBpbiBiYXNlbGluZSBnZW5vdHlwZXMgYW5kIHJlbW92ZSBsb2NpIGFuZCBpbmRpdmlkdWFscyB3aXRoIHRvbyBtdWNoIG1pc3NpbmcgZGF0YQoKYGBge3IgcmVhZC1zcHAtZ2Vub3N9CiMgcmVhZCBpbiBnZW5vdHlwZXMgaWRlbnRpZmllZCB0byBzcGVjaWVzIHVzaW5nIHJ1YmlhcwpzcHAgPC0gcmVhZF9jc3YoIi4uL2RhdGEvcmVwb3J0ZWRfaGFwbG90eXBlX1NlYlNwcElEXzExMTAyMDE3LmNzdiIpCgpzZWxlY3Rfc3BwIDwtIHNwcCAlPiUKICBzZWxlY3QoZ3JvdXAsIGxvY3VzLCBpbmRpdi5JRCwgaGFwbG90eXBlLjEsIGhhcGxvdHlwZS4yKQoKc3BwLmlkIDwtIHNlbGVjdF9zcHAgJT4lCiAgZ2F0aGVyKCJnZW5lX2NvcHkiLCAiYWxsZWxlIiwgNDo1KSAlPiUKICBtdXRhdGUoZ2VuZV9jb3B5ID0gaWZlbHNlKGdlbmVfY29weSA9PSAiaGFwbG90eXBlLjEiLCAxLCAyKSkKCiMgb25seSBrZWVwIHRoZSBsb2NpIHRoYXQgYXJlIG5vdCB0aGUgNiByZW1vdmVkIGZyb20gdGhlIHByZXZpb3VzIGRhdGFzZXQKc3BwLmlkX2xvYyA8LSBzcHAuaWQgJT4lCiAgYW50aV9qb2luKC4sIHRvX3JlbW92ZSwgYnkgPSAibG9jdXMiKQojIHRoYXQgc2hvdWxkIGxlYXZlIDkwIGxvY2kgCgoKIyByZW1vdmUgc2FtcGxlcyB3aXRoIG1pc3NpbmcgZGF0YSBhdCBtb3JlIHRoYW4gMTUgbG9jaSAocGVyIEhheWxleSdzIHdvcmtmbG93KQpzcHAuaWRfbm9fbWlzc2VycyA8LSBzcHAuaWRfbG9jICU+JQogIGdyb3VwX2J5KGluZGl2LklEKSAlPiUKICBmaWx0ZXIoc3VtKCFpcy5uYShhbGxlbGUpKSA+PSAoNzUqMikpCgoKIyBhZGQgcmVmZXJlbmNlIGNvbHVtbiB0byBwcmVwYXJlIGRhdGEgZm9yIHJ1YmlhcwpzcHAuaWRfbG9jMSA8LSBzcHAuaWRfbm9fbWlzc2VycyAlPiUKICBtdXRhdGUoc2FtcGxlX3R5cGUgPSAicmVmZXJlbmNlIikKCnggPC0gc3BwLmlkX2xvYzEgJT4lCiAgbXV0YXRlKHJlcHVuaXQgPSBncm91cCkKCiMgcmVvcmRlciB0aGUgY29sdW1ucwpzcHAuaWQxIDwtIHhbLGMoNiw3LDEsMywyLDQ6NSldCgpzcHAuaWQyIDwtIHNwcC5pZDEgJT4lCiAgcmVuYW1lKGNvbGxlY3Rpb24gPSBncm91cCkgJT4lCiAgcmVuYW1lKGluZGl2ID0gaW5kaXYuSUQpCgojIGNyZWF0ZSBhbiBhcnRpZmljaWFsIElEIGZvciB0aGUgc3BwLmlkCiNzcHAuaWQyIDwtIHNwcC5pZDEgJT4lCiMgIHVuaXRlKE5NRlNfRE5BX0lELCAxOjIpCgojIGdldCB0aGUgZGF0YSBmcmFtZXMgaW50byB0aGUgc2FtZSBmb3JtYXQKbm9faGlfbWlzc2VyczIgPC0gbm9faGlfbWlzc2VycyAlPiUKICBkcGx5cjo6c2VsZWN0KE5NRlNfRE5BX0lELCBsb2N1cywgZ2VuZV9jb3B5LCBhbGxlbGUpICU+JQogIHJlbmFtZShpbmRpdiA9IE5NRlNfRE5BX0lEKSAlPiUKICBtdXRhdGUoc2FtcGxlX3R5cGUgPSAibWl4dHVyZSIpICU+JQogIG11dGF0ZShyZXB1bml0ID0gTkEpICU+JQogIG11dGF0ZShjb2xsZWN0aW9uID0gIm9zdV9zYW1wbGVzIikKCiMgcmVvcmRlcgoKbm9faGlfbWlzc2VyczJbLCBjKDU6NywxOjQpXQoKIyBjb21iaW5lIHRoZSBkYXRhIGludG8gYSBzaW5nbGUgZGYKYWxsZWxlcyA8LSBiaW5kX3Jvd3Moc3BwLmlkMiwgbm9faGlfbWlzc2VyczIpCgphbGxlbGVzCmBgYAoKCldlIGFyZSBnb2luZyB0byBkbyB0aGlzIGJ5IHR1cm5pbmcgYWxsZWxlcyBpbnRvIGludGVnZXJzIGFuZCBzcHJlYWRpbmcgaXQgYW5kIHRoZW4gZ2V0dGluZyBpdCBpbnRvIHRoZSByaWdodCBmb3JtYXQgdG8gcnVuIHJ1Ymlhcy4KYGBge3Igc3ByZWFkLWdlbm9zfQojIGZpcnN0IG1ha2UgaW50ZWdlcnMgb2YgdGhlIGFsbGVsZXMKYWxsZV9pZHhzIDwtIGFsbGVsZXMgJT4lIAogICNkcGx5cjo6c2VsZWN0KE5NRlNfRE5BX0lELCBsb2N1cywgZ2VuZV9jb3B5LCBhbGxlbGUpICU+JQogIGdyb3VwX2J5KGxvY3VzKSAlPiUKICBtdXRhdGUoYWxsZWlkeCA9IGFzLmludGVnZXIoZmFjdG9yKGFsbGVsZSwgbGV2ZWxzID0gdW5pcXVlKGFsbGVsZSkpKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGFycmFuZ2UoaW5kaXYsIGxvY3VzLCBhbGxlaWR4KSAjIHJ1YmlhcyBjYW4gaGFuZGxlIE5BJ3MsIHNvIG5vIG5lZWQgdG8gY2hhbmdlIHRoZW0gdG8gMCdzCiAgCiMgc2VsZWN0IGp1c3QgdGhlIGNvbHVtbnMgdG8gcmV0YWluIGFuZCBzcHJlYWQgdGhlIGFsbGVsZXMKYWxsZV9pZHgyIDwtIGFsbGVfaWR4c1ssLTddCiAgCnR3b19jb2wgPC0gYWxsZV9pZHgyICU+JQogIHVuaXRlKGxvYywgbG9jdXMsIGdlbmVfY29weSwgc2VwID0gIi4iKSAlPiUKICBzcHJlYWQobG9jLCBhbGxlaWR4KQoKdHdvX2NvbAoKIyB3cml0ZSB0aGlzIGZpbGUgdG8gYSB0aGluZyB0aGF0IGNhbiBiZSByZWFkLWludG8gb3RoZXIgc29mdHdhcmVzCiN0d29fY29sICU+JQojIHdyaXRlX2NzdigiY3N2X291dHB1dHMvZ2Vub3NfdHdvX2NvbC5jc3YiKQpgYGAKCk9rYXksIGFmdGVyIHNvbWUgcmVhZGluZywgaXQgbG9va3MgbGlrZSBJIG5lZWQgdG8gdXNlIGBpbmZlcl9taXh0dXJlYCBpbiBydWJpYXMuCldoaWNoIHJlcXVpcmUgdHdvIHNlcGFyYXRlIGRhdGEgZnJhbWVzLCBvbmUgd2l0aCB0aGUgcmVmZXJlbmNlIGdlbm90eXBlcyBhbmQgdGhlIG90aGVyIHdpdGggdGhlIG1peHR1cmUuIAoKSSdsbCBzcGxpdCB0aGUgZGF0YSBmcmFtZSB0aGF0IEkgY3JlYXRlZCwgYnV0IGl0IG5lZWRlZCB0byBiZSBidW5nZWQgdG9nZXRoZXIgZm9yIHRoZSBjb252ZXJzaW9uIG9mIGFsbGVsZXMgdG8gaW50ZWdlcnMuCgpgYGB7ciBzcGxpdC1mcmFtZXN9CiMgc3BsaXQgdXAgdGhlIHJlZmVyZW5jZSBhbmQgbWl4dHVyZSBkYXRhIGZyYW1lcwpzcF9taXggPC0gdHdvX2NvbCAlPiUKICBmaWx0ZXIoc2FtcGxlX3R5cGUgPT0gIm1peHR1cmUiKQoKc3BfcmVmIDwtIHR3b19jb2wgJT4lCiAgZmlsdGVyKHNhbXBsZV90eXBlID09ICJyZWZlcmVuY2UiKQpgYGAKCgpgYGB7ciBydW4tcnViaWFzfQojIE5vdyB0aGF0IHRoZSBkYXRhIGFyZSBpbiB0aGUgY29ycmV0IGZvcm1hdCwgbG9hZCBSdWJpYXMKbGlicmFyeShydWJpYXMpCgojIHBlcmZvcm0gc2VsZi1hc3NpZ25tZW50IG9mIHJlZmVyZW5jZSBzYW1wbGVzCnJlZl9zZWxmIDwtIHNlbGZfYXNzaWduKHNwX3JlZiwgZ2VuX3N0YXJ0X2NvbCA9IDUpCgojIGFuZCB0YWtlIGEgcXVpY2sgbG9vayBhdCB0aG9zZSBhc3NpZ25tZW50cwpyZWZfc2VsZiAlPiUKICBmaWx0ZXIoaW5mZXJyZWRfcmVwdW5pdCA9PSByZXB1bml0KSAlPiUKICBmaWx0ZXIoc2NhbGVkX2xpa2VsaWhvb2QgPiAwLjk1KQoKYGBgCgpgYGB7ciBydW4tbWl4dHVyZX0KIyBwZXJmb3JtIG1peHR1cmUtYXNzaWdubWVudCBvbiBiYXNlbGluZSBjb2xvbnkgc2FtcGxlcwptaXhfYXNzaWduIDwtIGluZmVyX21peHR1cmUocmVmZXJlbmNlID0gc3BfcmVmLCBtaXh0dXJlID0gc3BfbWl4LCBnZW5fc3RhcnRfY29sID0gNSwgbWV0aG9kID0gIk1DTUMiLCByZXBzID0gMjAwMCwgYnVybl9pbiA9IDEwMCkKCiMgVGhhdCB3YXMgZmFzdCwgbGV0J3MgdGFrZSBhIGxvb2sKaGVhZChtaXhfYXNzaWduKQoKIyB0aGUgaW5kaXZpZHVhbCBkYXRhIGlzIGluIAptaXhfYXNzaWduJGluZGl2X3Bvc3RlcmlvcnMgJT4lCiAgYXJyYW5nZShkZXNjKGxvZ19saWtlbGlob29kKSkKCiMgYXJlIHRoZXJlIGFueSByb2NrZmlzaCB0aGF0IGRvbid0IHNlZW0gbGlrZSB0aGUgY29ycmVjdCBzcGVjaWVzIGlzIGluIHRoZSByZWZlcmVuY2U/Cm9zdV9hc3NpZ25tZW50cyA8LSBtaXhfYXNzaWduJGluZGl2X3Bvc3RlcmlvcnMgJT4lCiAgZmlsdGVyKFBvZlogPT0gMSkKCm9zdV9hc3NpZ24yIDwtIG9zdV9hc3NpZ25tZW50c1ssLTEwXQoKI3dyaXRlX2Nzdihvc3VfYXNzaWduMiwgImNzdl9vdXRwdXRzL29zdV9hc3NpZ25tZW50cy5jc3YiKQoKb3N1X2Fzc2lnbjIKYGBgCgpUaGUgcG9zdGVyaW9yIG1lYW5zIG9mIGdyb3VwIG1lbWJlcnNoaXAgaW4gZWFjaCBjb2xsZWN0aW9uIGlzIGluIHRoZSBQb2ZaIGNvbHVtbiAtIHRoZXJlIGFyZSAxLDIyMCBpbmRpdmlkdWFscyB3aXRoIGEgUG9mWiA9IDEuCgpgYGB7ciBjb21iaW5lLWJyaXR0YW55cy1kYXRhLXdpdGgtcnViaWFzLW91dHB1dH0KIyB3aGF0IEkgd2FudCB0byBkbyBoZXJlIGlzIGpvaW4gQnJpdHRhbnkncyBzYW1wbGUgc2hlZXQgd2l0aCB0aGUgcnViaWFzIGFzc2lnbm1lbnRzCgpicml0X2RhdGEgPC0gcmVhZF9leGNlbCgiLi4vZXh0ZGF0YS9icml0dGFueV9vc3Vfc2FtcGxlc2hlZXRzL09TVVJvY2tmaXNoX2d0c2VxX1NwZWNpZXNfSURfRGF0YS54bHN4IikKCmJyaXRfZGF0YSA8LSBicml0X2RhdGFbMToyMV0KCnRtcDEgPC0gb3N1X2Fzc2lnbjIgJT4lCiAgbGVmdF9qb2luKC4sIGJyaXRfZGF0YSwgYnkgPSBjKCJpbmRpdiIgPSAiTk1GU19ETkFfSUQiKSkKCmJyaXRfYXNzaWduIDwtIHRtcDFbMToyMV0KCiMgd2hpY2ggb2YgYnJpdHRhbnkncyBzYW1wbGVzIHN0aWxsIGRvbid0IGhhdmUgZ2Vub3R5cGUgaW5mbz8KYnJpdF9kYXRhICU+JQogIGFudGlfam9pbiguLCBvc3VfYXNzaWduMiwgYnkgPSBjKCJOTUZTX0ROQV9JRCIgPSAiaW5kaXYiKSkKYGBgCgpNYXliZSBzb21lIG9mIHRoZXNlIHNhbXBsZXMganVzdCBoYWQgYSBQb2ZaIGxhcmdlci9zbWFsbGVyIHRoYW4gMT8KKGV2ZW50dWFsbHkgSSB3aWxsIHVwZGF0ZSBgYnJpdF9kYXRhYCB3aXRoIGFsbCBvZiB0aGUgYXBwcm9wcmlhdGUgbWV0YSBkYXRhIGZvciB0aGlzIHByb2plY3QuKQoKYGBge3IgbGVzc2VyLWFzc2lnbm1lbnRzfQojIEkgdGhpbmsgdGhlcmUgYXJlIGluZGl2aWR1YWwgYXNzaWdubWVudHMgZm9yIGVhY2ggc2FtcGxlIHRvIGVhY2ggcmVmZXJlbmNlLgojIEkgd2FudCB0byB0YWtlIG9ubHkgdGhlIHRvcCBhc3NpZ25tZW50IGZvciBlYWNoIHNhbXBsZS4Ka2VwdF9hc3NpZ25tZW50cyA8LSBtaXhfYXNzaWduJGluZGl2X3Bvc3RlcmlvcnMgJT4lCiAgZ3JvdXBfYnkoaW5kaXYpICU+JQogIGZpbHRlcihQb2ZaID4gMC45NSkgJT4lCiAgYXJyYW5nZShkZXNjKFBvZlopKQoKa2VwdF9hc3NpZ25tZW50cwpgYGAKVXNpbmcgSGF5bGV5J3MgdGhyZXNob2xkIG9mIDAuOTUgZm9yIHRoZSBQb2ZaLCB3ZSBoYXZlIDEsNDM1IGluZGl2aWR1YWxzIHJldGFpbmVkLgoKTm93IHRha2UgYSBsb29rIGF0IHdoaWNoIGZpc2ggZnJvbSBCcml0dGFueSdzIHNhbXBsZXMgYXJlIGluY2x1ZGVkOgpgYGB7ciBicml0cy1hc3NpZ25lbW50c30KIyB1c2luZyB0aGUgZGF0YSBJIHJlYWQgaW4gcHJldmlvdXNseQp0bXAyIDwtIGtlcHRfYXNzaWdubWVudHMgJT4lCiAgbGVmdF9qb2luKC4sIGJyaXRfZGF0YSwgYnkgPSBjKCJpbmRpdiIgPSAiTk1GU19ETkFfSUQiKSkKCmJyaXRfYXNzaWduIDwtIHRtcDJbMToyMV0KCiMgd2hpY2ggb2YgYnJpdHRhbnkncyBzYW1wbGVzIHN0aWxsIGRvbid0IGhhdmUgZ2Vub3R5cGUgaW5mbz8KYnJpdF9kYXRhICU+JQogIGFudGlfam9pbiguLCBrZXB0X2Fzc2lnbm1lbnRzLCBieSA9IGMoIk5NRlNfRE5BX0lEIiA9ICJpbmRpdiIpKQoKYGBgClRoYXQgZGlkbid0IGluY3JlYXNlIHRoZSBudW1iZXIgb2Ygc2FtcGxlcyByZXRhaW5lZCBieSBtdWNoLi4uIAoKQXJlIHRoZXJlIHJlYWxseSAzNzUgc2FtcGxlcyB0aGF0IGRvbid0IGhhdmUgZ2Vub3R5cGVzPwoKYGBge3IgbG9vay1hdC1hbGwtYXNzaWdubWVudHN9CmFsbF9hc3NpZ24gPC0gbWl4X2Fzc2lnbiRpbmRpdl9wb3N0ZXJpb3JzICU+JQogIGdyb3VwX2J5KGluZGl2KQoKIyB3aGljaCBvZiBicml0dGFueSdzIHNhbXBsZXMgZG9uJ3QgaGF2ZSBnZW5vdHlwZSBpbmZvPwpicml0X2RhdGEgJT4lCiAgYW50aV9qb2luKC4sIGFsbF9hc3NpZ24sIGJ5ID0gYygiTk1GU19ETkFfSUQiID0gImluZGl2IikpCgpgYGAKT2theSwgdGhvc2UgMzc1IHNhbXBsZXMganVzdCBhcmVuJ3QgaW4gdGhlIGRhdGEgc2V0LiBUaGV5J3JlIG5vdCBqdXN0IGZpbHRlcmVkIG91dCBieSB0aGUgMC45NSBQb2ZaIGFzc2lnbm1lbnQgdGhyZXNob2xkLgoKYGBge3IgY29tcGFyZS1icml0LWFzc2lnbn0KaGVhZChicml0X2RhdGEpICMgaGVyZSBpcyB0aGUgIlNQRUNJRVMiIGNvbHVtbgoKa2VwdF9hc3NpZ25tZW50cyAlPiUKICBsZWZ0X2pvaW4oLiwgYnJpdF9kYXRhLCBieSA9IGMoImluZGl2IiA9ICJOTUZTX0ROQV9JRCIpKSAlPiUKICBzZWxlY3QoMTo5LDExOjMwKSAlPiUKICB3cml0ZV9jc3YoImNzdl9vdXRwdXRzL29zdV9rZXB0X2Fzc2lnbm1lbnRzLmNzdiIpCiAgCmBgYAoKCiMjIFJlcG9zaXRvcnkgbWV0YSBkYXRhIGZvciBCcml0dGFueSdzIHNhbXBsZXMKCmBgYHtyIGFkZC1tZXRhLWRhdGF9CmJhdGNoXzQ3OTIgPC0gcmVhZF9jc3YoIi4uL2V4dGRhdGEvYmF0Y2g0NzkyLmNzdiIpCmJhdGNoXzQ5NjkgPC0gcmVhZF9jc3YoIi4uL2V4dGRhdGEvYmF0Y2g0OTY5LmNzdiIpCgojIHNvbWVob3cgdGhlIHN0cnVjdHVyZSBmb3IgdGhlIHNhbXBsZSBJRHMgaXMgZGlmZmVyZW50IGluIHRoZSB0d28gZmlsZXMuLi4KIyBjaGFuZ2UgdGhhdC4KYmF0Y2hfNDc5MiRTQU1QTEVfSUQgPC0gYXMuY2hhcmFjdGVyKGJhdGNoXzQ3OTIkU0FNUExFX0lEKQoKIyBiaW5kIHRob3NlIHRoaW5ncyB0b2dldGhlcgptZXRhIDwtIGJpbmRfcm93cyhiYXRjaF80OTY5LCBiYXRjaF80NzkyKQoKYGBgCgpUaGUgYG1ldGFgIGZpbGUgc2hvdWxkIGNvbnRhaW4gYWxsIHRoZSBzYW1wbGVzIGZvciBCcml0dGFueSdzIHByb2plY3QuCgpgYGB7ciBtZXRhLWFzc2lnbn0KYnJpdF9hbGxfYXNzaWduIDwtIG1ldGEgJT4lCiAgbGVmdF9qb2luKC4sIGtlcHRfYXNzaWdubWVudHMsIGJ5ID0gYygiTk1GU19ETkFfSUQiID0gImluZGl2IikpCgpicml0X2FsbF9hc3NpZ24gJT4lCiAgc2VsZWN0KDE6NSw3OjksMTcsMjU6MzApICU+JQogIHdyaXRlX2NzdigiY3N2X291dHB1dHMvYnJpdHRhbnlfZXN0dWFyeV9hc3NpZ25tZW50cy5jc3YiKQoKIyBhbmQgYSBsaXN0IG9mIHRoZSBzYW1wbGVzIHRoYXQgd2VyZSBub3QgYXNzaWduZWQgKGZvciBvbmUgcmVhc29uIG9yIGFub3RoZXIpCmJyaXRfbWlzc2luZyA8LSBicml0X2FsbF9hc3NpZ24gJT4lCiAgYW50aV9qb2luKC4sIGtlcHRfYXNzaWdubWVudHMsIGJ5ID0gYygiTk1GU19ETkFfSUQiID0gImluZGl2IikpICU+JQogICNncm91cF9ieShCT1hfSUQpICU+JQogICN0YWxseSgpIAogIHNlbGVjdCgxOjMwKSAjJT4lCiAgI3dyaXRlX2NzdigiY3N2X291dHB1dHMvYnJpdHRhbnlfdW5hc3NpZ25lZF9zYW1wbGVzLmNzdiIpCiAgCmBgYAoxOTIgc2FtcGxlcy4gVGhhdCdzIHN0aWxsIGFuIHVuZm9ydHVuYXRlIGxvdC4KSSB3b25kZXIgaWYgdGhleSBhcmUgdGhlIHNhbWUgc2FtcGxlcyB0aGF0IGRpZG4ndCBnZW5vdHlwZSB3ZWxsIGxhc3QgdGltZT8KCmBgYHtyIGNoYW5nZS10aHJlc2hvbGR9CiMgaWYgdGhlIGFzc2lnbm1lbnQgdGhyZXNob2xkIGlzIGxvd2VyIHRoYW4gMC45NSwgdGhhdCBtaWdodCBpbmNsdWRlIG1vcmUgc2FtcGxlcz8Kb2tfYXNzaWdubWVudHMgPC0gbWl4X2Fzc2lnbiRpbmRpdl9wb3N0ZXJpb3JzICU+JQogIGdyb3VwX2J5KGluZGl2KSAlPiUKICBmaWx0ZXIoUG9mWiA+IDAuODApICU+JQogIGFycmFuZ2UoZGVzYyhQb2ZaKSkKCiMgYW5kIGpvaW4gdGhvc2UgdG8gQnJpdHRhbnkncyBzYW1wbGVzCmJyaXRfYWxsX2Fzc2lnbiAlPiUKICBhbnRpX2pvaW4oLiwgb2tfYXNzaWdubWVudHMsIGJ5ID0gYygiTk1GU19ETkFfSUQiID0gImluZGl2IikpCgpgYGAKU3RpbGwgMTkyIHNhbXBsZXMhCgpPZiBwcmltYXJ5IGNvbmNlcm4gaXMgd2hldGhlciB3ZSBhY3R1YWxseSBnZW5vdHlwZWQgdGhlc2UgYXQgYWxsLiBMZXQncyBnbyBiYWNrIHRvIHRoZSBkYXRhLgpgYGB7ciBzYW1wbGVzLXJ1bn0Kc2FtcGxlcyAlPiUKICBhbnRpX2pvaW4oLiwgYnJpdF9hbGxfYXNzaWduLCBieSA9ICJOTUZTX0ROQV9JRCIpCiMgNjg2IHNhbXBsZXMgdGhhdCB3ZXJlIHJ1biB0aGF0IHdlcmUgbm90IGJyaXR0YW55J3MuCgpicml0X2FsbF9hc3NpZ24gJT4lCiAgYW50aV9qb2luKC4sIHNhbXBsZXMsIGJ5ID0gIk5NRlNfRE5BX0lEIikKIyAwIHNhbXBsZXMgb2YgYnJpdHRhbnkncyB0aGF0IHdlcmUgbm90IHJ1bi4KIyB3ZWxsLCBhdCBsZWFzdCB0aGF0J3MgZ29vZC4KCiMgbm93IGNoZWNrIGdlbm90eXBlcwpicml0X2FsbF9hc3NpZ24gJT4lCiAgYW50aV9qb2luKC4sIGdlbm9zLCBieSA9ICJOTUZTX0ROQV9JRCIpCiMgYWxsIG9mIGJyaXR0YW55J3Mgc2FtcGxlcyBoYWQgZ2Vub3R5cGVzIHRoYXQgd2VyZSByZWFkIGluIGZyb20gdGhlIHJkcyBmaWxlcy4KCiMgd2hlcmUgd2VyZSB0aGV5IGtpY2tlZCBvdXQ/CmhpX21pc3NlcnMgPC0gYnJpdF9hbGxfYXNzaWduICU+JQogIGFudGlfam9pbiguLCBub19oaV9taXNzZXJzLCBieSA9ICJOTUZTX0ROQV9JRCIpCgptaXNzZXJzX2xvY2kgPC0ga2VlcGVycyAlPiUgIyBrZWVwZXJzIGlzIHRoZSBkYXRhIGZyYW1lIGFmdGVyIHJlbW92aW5nIDYgbG9jaQogIGlubmVyX2pvaW4oLiwgaGlfbWlzc2VycywgYnkgPSAiTk1GU19ETkFfSUQiKSAlPiUKICBncm91cF9ieShOTUZTX0ROQV9JRCkgJT4lCiAgc2VsZWN0KE5NRlNfRE5BX0lELCBhbGxlbGUpICU+JQogIHRhbGx5KGlzLm5hKGFsbGVsZSkpICU+JQogIG11dGF0ZShtaXNzaW5nX2xvY2kgPSBuLzIpCgojIHRoZXJlIHNob3VsZG4ndCBiZSBhbnkgbWlzc2VycyB3aXRoIDwgMTUgbWlzc2luZyBsb2NpCm1pc3NlcnNfbG9jaSAlPiUKICBmaWx0ZXIobWlzc2luZ19sb2NpIDwgMTUpIAogIAojIHN0aWNrIHRoYXQgZGF0YSB0YWJsZSBvbnRvIHRoZSAxOTIgc2FtcGxlcyB3aXRoIHRvbyBtdWNoIG1pc3NpbmcgZGF0YQptaXNzZXJzX2xvY2kgJT4lCiAgbGVmdF9qb2luKC4sIGJyaXRfbWlzc2luZywgYnkgPSAiTk1GU19ETkFfSUQiKSAlPiUKICBzZWxlY3QoMSwzOjE3LDE5LDIxOjI0KSAlPiUKICB3cml0ZV9jc3YoImNzdl9vdXRwdXRzL09TVV91bmFzc2lnbmVkX21pc3NpbmdfZGF0YS5jc3YiKQoKYGBgCll1cC4gVGhlIDE5MiBzYW1wbGVzIGFyZSBpbiB0aGUgaGktbWlzc2VycyBkYXRhIC0gdGhleSBoYWQgbG90cyBvZiBtaXNzaW5nIGdlbm90eXBlcy4KCgojIyBMb29raW5nIGF0IHRoZSBzdWNjZXNzIG9mIHJlLWdlbm90eXBlZCBzYW1wbGVzCgpgYGB7ciB0b3NzZXJzfQojIGp1c3QgdGhlIHNhbXBsZXMgZnJvbSBndHNlcSA2MwpndHNlcTYzIDwtIHNhbXBsZXMgJT4lCiAgZmlsdGVyKGd0c2VxX3J1biA9PSAiZ3RzZXE2MyIpCgojIG5vdyBhZGQgYXNzaWdubWVudHMganVzdCBmb3IgdGhvc2Ugc2FtcGxlcwpndHNlcTYzICU+JQogIGxlZnRfam9pbiguLCBrZXB0X2Fzc2lnbm1lbnRzLCBieSA9IGMoIk5NRlNfRE5BX0lEIiA9ICJpbmRpdiIpKSAlPiUKICBzZWxlY3QoMToyLCA1OjcsIDE3OjIyKSAlPiUKICAjd3JpdGVfY3N2KCJjc3Zfb3V0cHV0cy9ndHNlcTYzX2Fzc2lnbm1lbnRzLmNzdiIpCiAgZmlsdGVyKHNzQk9YX0lEID09ICJSMzc0IikgIyU+JQogICN3cml0ZV9jc3YoImNzdl9vdXRwdXRzL2d0c2VxNjNfUjM3NF9hc3NpZ25tZW50cy5jc3YiKQoKYGBgCkhlcmUncyB3aGF0IENhc3NpZSBzYWlkIHdhcyBpbiB0aGF0IHJ1bjoKVGhpcyBydW4gaGFzIGJveCBSMzczIGFuZCB0d28gbWl4ZWQgcGxhdGVzICgxIG9mIHRob3NlIG1peGVkIHBsYXRlcyBpcyBwYXJ0aWFsKS4gClBsYXRlIDEgaGFzIHRoZSBzYW1wbGVzIGZyb20gcGxhdGUgUjM3NCB0aGF0IG5lZWQgc3BlY2llcyBJRCDigJMgQnJpdHRhbnkncyBzYW1wbGVzIGluIGAxQSAtIDNBYDsgc2FtcGxlcyBmb3IgSGVsZW4gS2lsbGVlbiBpbiBgM0IgLSA0QWA7IHR3byByZS1waWNrcyBmcm9tIHlvdXIgTkZTIHByb2plY3QgaW4gYDRCYCBhbmQgYDRDYDsgYW5kIE9ORSB0ZW50YXRpdmUgTWV4aWNhbiByb2NrZmlzaCBpbiBgNERgLiBJdCBhbHNvIGhhcyByZS1ydW5zIGZvciBCcml0dGFueSdzIHByb2plY3QuIFRoZSB0d28gTlNGIHJlLXBpY2tzIGFyZSBoaWdobGlnaHRlZCBpbiB0aGUgYXR0YWNoZWQgbGlzdCBvZiBibGFjayBhbmQgeWVsbG93IHNpYnMgdGhhdCB5b3UgZ2F2ZSBtZS4gV2UgcmUtZXh0cmFjdGVkIHRoZXNlIHNpbmNlIHRoZXJlIHdhcyB0aXNzdWUgcmVtYWluaW5nIGFuZCB3ZSBhbHNvIHJlLXJhbiB0aGUgb3JpZ2luYWwgRE5BIGV4dHJhY3RzIGluIHRoaXMgcnVuLiAKUGxhdGUgMnJyIGFyZSBhbGwgcmUtcnVucyBpbmNsdWRpbmcgeW91ciBOU0YgYmxhY2sgYW5kIHllbGxvdyBzaWJzIGFuZCB0aGUgcmVzdCBvZiB0aGUgZmFpbGVkIHNhbXBsZXMgZnJvbSBCYWlsZXkncyBydW4gZm9yIEJyaXR0YW55J3MgcHJvamVjdC4gCgpgYGB7ciBlYXNpZXItZm9ybWF0fQpndHNlcTYzICU+JQogIGZpbHRlcihzc0JPWF9JRCA9PSAiUjI4MiIpCmBgYAoKYGBge3IgcmUtcnVuc30KIyB3aGljaCBzYW1wbGVzIGZyb20gZ3RzZXE2MyBkb24ndCBoYXZlIGtlcHQgYXNzaWdubWVudHM/Cmd0c2VxNjMgJT4lCiAgYW50aV9qb2luKC4sIGtlcHRfYXNzaWdubWVudHMsIGJ5ID0gYygiTk1GU19ETkFfSUQiID0gImluZGl2IikpICU+JQogIGZpbHRlcihzc0JPWF9JRCA9PSAiUjEzMyIpCgpgYGAKQWxsIHRoZSBzYW1wbGVzIGZyb20gUjM3MyB3ZXJlIG5vdCByZS1ydW5zLiAoMjMgc2FtcGxlcykKVGhlIDQgc2FtcGxlcyB0aGF0IGZhaWxlZCBmcm9tIFIzNzQgd2VyZSBmb3IgSGVsZW4gS2lsbGVlbi4KCjQ3IC0yNyA9IDIwIHNhbXBsZXMgdGhhdCBmYWlsZWQgZnJvbSB0aGUgcmUtcnVucz8gV2FzIHRoYXQgb3V0IG9mIDEwOCB0b3RhbD8KCkFuZCBpZiB3ZSBkaWQgcmUtcnVuIGFsbCBvZiBCcml0dGFueSdzIGZpc2ggZnJvbSBwcmV2aW91cyBydW5zLCBpcyB0aGUgbWFqb3JpdHkgb2YgdGhlIG1pc3NpbmcgZGF0YSBmcm9tIHRoZSBuZXcgc2FtcGxlcz8gCgo=